#include "cv.h"
#include "highgui.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <ctype.h>


class SkinDetector{
	IplImage *outMask;
	static const int radOpening=8;
	static const int radClosing=10;

	IplImage *imageR;
	IplImage *imageG;
	IplImage *imageB;
    IplImage *imgH, *imgS, *imgV, *imgHSV;
	IplImage *tmp1;
	IplImage *tmp2 ;
	IplImage *th1;
	IplImage *th2;
	IplImage *opened;
	IplImage *closed;
	IplImage *img_smoothed;
	IplConvKernel* element1;
	IplConvKernel* element2;
public:
	SkinDetector(CvSize &size)
	{
		imageR = cvCreateImage(size, 8,1); 
		imageG = cvCreateImage(size, 8,1); 
		imageB = cvCreateImage(size, 8,1); 
        imgH = cvCreateImage(size, 8,1);
		imgS = cvCreateImage(size, 8,1);
		imgV = cvCreateImage(size, 8,1);
		imgHSV = cvCreateImage(size, 8,3);
		img_smoothed = cvCreateImage(size, 8, 3);
		
        tmp1 = cvCreateImage(size, 8,1);
		tmp2 = cvCreateImage(size, 8,1);
		th1 = cvCreateImage(size, 8,1);
		th2 = cvCreateImage(size, 8,1);
		opened = cvCreateImage(size, 8,1);
		closed = cvCreateImage(size, 8,1);
		outMask = 0;

		element1 = cvCreateStructuringElementEx(radOpening,radOpening,(float)radOpening/2,radOpening/2,CV_SHAPE_ELLIPSE,NULL);
		element2 = cvCreateStructuringElementEx(radClosing,radClosing,(float)radClosing/2,radClosing/2,CV_SHAPE_ELLIPSE,NULL);
	}
	~SkinDetector()
	{
		cvReleaseImage(&outMask);
		cvReleaseImage(&imageR);
		cvReleaseImage(&imageG);
		cvReleaseImage(&imageB);
		cvReleaseImage(&tmp1);
		cvReleaseImage(&tmp2);
		cvReleaseImage(&th1);
		cvReleaseImage(&th2);
		cvReleaseImage(&opened);
		cvReleaseStructuringElement(&element1);
		cvReleaseStructuringElement(&element2);
	}

	void run(IplImage *image, IplImage *mask=NULL)
	{
		//cvSmooth(image, img_smoothed, CV_MEDIAN, 5);
		cvSmooth(image, img_smoothed, CV_GAUSSIAN, 5,5);
        cvCvtColor(img_smoothed, imgHSV, CV_BGR2HSV);
        cvSplit(imgHSV, imgH, imgS, imgV, NULL);
        //cvThreshold(imgH, th1, 6,255,CV_THRESH_TOZERO);
		cvThreshold(imgH, th1, 20,255,CV_THRESH_BINARY_INV);
        cvThreshold(imgV, th2, 240,255, CV_THRESH_BINARY);
        cvSub(th1, th2, tmp1);
        cvThreshold(imgV, th2, 10,255, CV_THRESH_BINARY_INV);
        cvSub(tmp1, th2, tmp2);
        
		
        
		//cvCvtPixToPlane(image, imageR, imageG, imageB, NULL);
		//cvSub(imageG, imageR, tmp1);
		//cvSub(imageB, imageR, tmp2);
		//cvThreshold(tmp1, th1, 5,255,CV_THRESH_BINARY);
		//cvThreshold(tmp2, th2, 5,255,CV_THRESH_BINARY);
		//cvZero(tmp1);
		//cvAdd(th1,th2,tmp1, mask);
	
		cvSmooth(tmp2, tmp1, CV_MEDIAN, 5);
		cvMorphologyEx(tmp1, closed, tmp1, element1, CV_MOP_OPEN ); 
		//cvMorphologyEx(tmp2, closed, tmp1, element2, CV_MOP_CLOSE );

#if 0
		cvNamedWindow("Skin detector");
		cvShowImage("Skin detector", closed);
		cvNamedWindow("H");
        cvShowImage("H", tmp1);
#endif
        //cvNamedWindow("V");
        //cvShowImage("V", imgV);
		outMask = closed;
	}
	
	inline IplImage *getMask() {return outMask;}

};